package com.yygo.jobs;

import com.yygo.Constants;
import com.yygo.model.Activity;
import com.yygo.model.LoanRequest;
import com.yygo.model.User;
import com.yygo.model.enums.Phase;
import com.yygo.model.enums.RequestStatus;
import com.yygo.service.LoanRequestManager;
import com.yygo.service.UserManager;
import com.yygo.util.DateUtil;
import com.yygo.util.SMSUtil;
import org.apache.activemq.ScheduledMessage;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.MessageSource;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.scheduling.quartz.QuartzJobBean;

import javax.jms.*;
import java.util.*;

/**
 * Created by tiansha on 2015/10/6.
 */
//@DisallowConcurrentExecution
public class MsgJob /*extends QuartzJobBean*/ {
    private static Log log = LogFactory.getLog(MsgJob.class);

    @Autowired
    private UserManager userManager = null;
    @Autowired
    private LoanRequestManager loanRequestManager = null;

    private MessageSource messageSource;

    private MessageSourceAccessor messages;

    @Autowired
    private JmsTemplate jmsTemplate;

    @Autowired
    private Destination destination;


    public void setUserManager(UserManager userManager) {
        this.userManager = userManager;
    }

    public void setLoanRequestManager(LoanRequestManager loanRequestManager) {
        this.loanRequestManager = loanRequestManager;
    }

    @Autowired
    public void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
        messages = new MessageSourceAccessor(messageSource);
    }

    //@Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        try {
            //ApplicationContext appCtx = getApplicationContext(context);

            /*userManager = (UserManager)appCtx.getBean("userManager");
            loanRequestManager = (LoanRequestManager)appCtx.getBean("loanRequestManager");
            messageSource = (MessageSource)appCtx.getBean("messageSource");*/
            messages = new MessageSourceAccessor(messageSource);

            // get all loanrequest for slave
            Set<LoanRequest> loanRequests = loanRequestManager.getRequestsForSlave();
            for (LoanRequest loanRequest : loanRequests) {
                processLoanRequest(loanRequest);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public void processLoanRequest(LoanRequest loanRequest) throws IllegalAccessException {
        Date currentDate = new Date();
        Calendar currentCalendar = Calendar.getInstance();
        currentCalendar.setTime(currentDate);
        int currHour = currentCalendar.get(Calendar.HOUR);

        Date auditDate = loanRequest.getAuditDate();
        if (auditDate == null)
            return;

        Calendar auditCalendar = Calendar.getInstance();
        auditCalendar.setTime(auditDate);
        // if audit date is one day before, auto audit
        currentCalendar.roll(Calendar.DATE, false);
        boolean auto = false;
        if (currentCalendar.getTime().getTime() >= auditDate.getTime()) {
            // auto audit
            autoAudit(loanRequest);
            auto = true;
        } else {

            int hour = auditCalendar.get(Calendar.HOUR);
            if (hour <= 17) {
                auditCalendar.add(Calendar.HOUR, 1);
                if (auditCalendar.getTime().getTime() == currentDate.getTime()) {
                    // send message
                    //sendMessage1(loanRequest);
                } else {
                    auditCalendar.add(Calendar.HOUR, 1);
                    if (auditCalendar.getTime().getTime() <= currentDate.getTime()) {
                        // auto audit
                        autoAudit(loanRequest);
                        auto = true;
                    }
                }
            } else if (currHour == 10) {
                // auto audit
                autoAudit(loanRequest);
                auto = true;
            }
        }
        if (auto) {
            loanRequestManager.saveLoanRequest(loanRequest);
        }
    }

    public void autoAudit(LoanRequest loanRequest) throws IllegalAccessException{
        if (loanRequest.getPhase().equals(Phase.qualification_audit)) {
            User auditUser = loanRequest.getDealer().getMasterProvider().getBondUser();
            transferStatus(loanRequest, RequestStatus.request_audit, Phase.insurance_confirm_cover, auditUser, Constants.Insurance_ROLE);
            loanRequestManager.saveLoanRequest(loanRequest);

            // notify master slave
            _sendQualificationAuditMessageToMaster(loanRequest);
        }
    }

    public void sendConfirmCoverMessageToSlave(LoanRequest loanRequest, int times) throws IllegalAccessException{
        // check if request is approved, if not, send message
        log.debug("send message for " + loanRequest.getNumber());
        boolean audited = true;
        if (loanRequest.getPhase().equals(Phase.insurance_confirm_cover)) {
            audited = false;
        }
        if (!audited) {
            if (_shouldSendMessage(loanRequest, times)) {
                _sendConfirmCoverMessageToSlave(loanRequest);
                // calculate auto audit time
                long time = 1000 * 60 * 30;
                sendDelayedMessage(loanRequest, time, Constants.MSG_TYPE_MESSAGE_CONFIRM_COVER, ++times);
            }
        }
    }

    private boolean _shouldSendMessage(LoanRequest loanRequest, int times) {
        if (times >= 12) // after 6 hours
            return false;
        else {
            Date currentDate = new Date();
            Calendar currentCalendar = Calendar.getInstance();
            currentCalendar.setTime(currentDate);

            if (currentCalendar.get(Calendar.HOUR) > 18) // until 18pm
                return false;
        }
        return true;
    }

    public void sendUploadPolicyMessageToMaster(LoanRequest loanRequest) {
        log.debug("send message for " + loanRequest.getNumber());
        boolean audited = true;
        if (loanRequest.getPhase().equals(Phase.insurance_upload_policy)) {
            audited = false;
        }
        if (!audited) {
            _sendUploadPolicyMessageToMaster(loanRequest);
        }
    }

    public void sendQualificationAuditMessageToMaster(LoanRequest loanRequest) {
        log.debug("send message for " + loanRequest.getNumber());
        boolean audited = true;
        if (loanRequest.getPhase().equals(Phase.qualification_audit)) {
            audited = false;
        }
        if (!audited) {
            _sendQualificationAuditMessageToMaster(loanRequest);
        }
    }

    private void _sendConfirmCoverMessageToSlave(LoanRequest loanRequest) {
        // send message;
        log.debug("sendConfirmCoverMessageToSlave");
        SMSUtil.sendConfirmCoverMessage(loanRequest.getDealer().getSlaveProvider().getBondUser().getPhoneNumber(), loanRequest.getNumber(), loanRequest.getRequestPerson().getName(), "" + loanRequest.getLoanAmount());
    }

    public void _sendQualificationAuditMessageToMaster(LoanRequest loanRequest) {
        // send message;
        log.debug("sendQualificationAuditMessageToMaster");
        SMSUtil.sendUploadCoverMessage(loanRequest.getDealer().getMasterProvider().getBondUser().getPhoneNumber(), loanRequest.getNumber(),
                loanRequest.getRequestPerson().getName(), "" + loanRequest.getLoanAmount());
    }

    private void _sendUploadPolicyMessageToMaster(LoanRequest loanRequest) {
        // send message;
        log.debug("sendUploadPolicyMessageToMaster");
        SMSUtil.sendConfirmPolicyMessage(loanRequest.getDealer().getMasterProvider().getBondUser().getPhoneNumber(), loanRequest.getNumber(),
                loanRequest.getRequestPerson().getName(), "" + loanRequest.getLoanAmount(), DateUtil.convertDateToString(loanRequest.getLoanDate()));
    }

    private User getHistoryUser(LoanRequest loanRequest, String role) throws IllegalAccessException {
        log.debug("auto audit for " + loanRequest.getNumber());
        User auditUser;
        String username = null;
        for (Activity activity : loanRequest.getActivities()) {
            if (activity.getRole().equals(role))
                username = activity.getOperator();
        }
        if (username != null) {
            auditUser = userManager.getUserByUsername(username);
        } else {
            // throw new IllegalAccessException("request not processed by any CA");
            log.debug("request not processed by any CA");
            auditUser = null;
        }
        return auditUser;
    }

    private void transferStatus(LoanRequest loanRequest, RequestStatus status, Phase phase, User auditUser, String role) {
        loanRequest.setStatus(status);
        loanRequest.setPhase(phase);
        loanRequest.setAuditDate(new Date());
        String readableStatus = getText("PHASE_".concat(phase.toString()), Locale.SIMPLIFIED_CHINESE);
        // add activity
        String activity = getText("loanRequest.activity.transferPhase", readableStatus, Locale.SIMPLIFIED_CHINESE);
        if (auditUser != null) {
            loanRequest.setAuditUser(auditUser);
            activity = getText("loanRequest.activity.transferPhaseAndOperator", new String[]{readableStatus, auditUser.getUsername()}, Locale.SIMPLIFIED_CHINESE);
        }
        Activity activityObj = new Activity("auto", activity);
        activityObj.setRole(role);
        activityObj.setLoanRequest(loanRequest);
        loanRequest.getActivities().add(activityObj);
    }

    private String getText(String msgKey, Locale locale) {
        return messages.getMessage(msgKey, locale);
    }

    private String getText(String msgKey, String arg, Locale locale) {
        return getText(msgKey, new Object[]{arg}, locale);
    }

    private String getText(String msgKey, Object[] args, Locale locale) {
        return messages.getMessage(msgKey, args, locale);
    }

    private void sendDelayedMessage(final LoanRequest loanRequest, long time, String msgType, int times) {
        jmsTemplate.setDeliveryMode(DeliveryMode.PERSISTENT);
        jmsTemplate.send(destination, new MessageCreator() {
            @Override
            public Message createMessage(Session session) throws JMSException {
                Message message = session.createMessage();
                //long time = 1000 * 60 * 60 * 2;
                message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time);
                message.setLongProperty("reqId", loanRequest.getId());
                message.setStringProperty("type", msgType);
                message.setIntProperty("times", times);
                return message;
            }
        });
    }



    /*private static final String APPLICATION_CONTEXT_KEY = "applicationContext";
    private ApplicationContext getApplicationContext(JobExecutionContext context) throws Exception {
        ApplicationContext appCtx = null;
        appCtx = (ApplicationContext) context.getScheduler().getContext().get(APPLICATION_CONTEXT_KEY);
        if (appCtx == null) {
            throw new JobExecutionException("No application context available in scheduler context for key \"" + APPLICATION_CONTEXT_KEY + "\"");
        }
        return appCtx;
    }*/
}
